package com.engine.cn.juc;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * AQS实现对线程的可控
 * Semaphore（信号量）之所以能与线程建立紧密联系，本质上是因为它完美解决了多线程环境下的两大核心问题：资源竞争和执行顺序协调
 * 红灯 = acquire()阻塞线程（禁止通行）
 * 车道数量 = 信号量的许可数（permits）
 * 绿灯 = release()放行线程（允许通行）
 */
public class SemaphoreOrderedThread {
    Semaphore fooSema = new Semaphore(1);
    Semaphore barSema = new Semaphore(0);
    Semaphore larSema = new Semaphore(0);

    public void foo() throws InterruptedException {
        int index = 0;
        while (index < 100) {
            fooSema.acquire();
            System.out.println("foo");
            index++;
            barSema.release();
        }
    }

    public void bar() throws InterruptedException {
        int index = 0;
        while (index < 100) {
            barSema.acquire();
            System.out.println("bar");
            index++;
            larSema.release();
        }
    }

    public void lar() throws InterruptedException {
        int index = 0;
        while (index < 100) {
            larSema.acquire();
            System.out.println("lar");
            index++;
            fooSema.release();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        SemaphoreOrderedThread aqs = new SemaphoreOrderedThread();
        executor.submit(() -> {
            try {
                aqs.foo();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        executor.submit(() -> {
            try {
                aqs.bar();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        executor.submit(() -> {
            try {
                aqs.lar();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        executor.shutdown();
        boolean result = executor.awaitTermination(1, TimeUnit.MINUTES); // 等待所有任务完成
        System.out.println(result);
    }
}
